home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / mawk10.zip / FIN.C < prev    next >
C/C++ Source or Header  |  1991-10-05  |  12KB  |  473 lines

  1.  
  2. /********************************************
  3. fin.c
  4. copyright 1991, Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the AWK programming language.
  8.  
  9. Mawk is distributed without warranty under the terms of
  10. the GNU General Public License, version 2, 1991.
  11. ********************************************/
  12.  
  13. /*$Log:    fin.c,v $
  14.  * Revision 3.5.1.1  91/09/14  17:23:21  brennan
  15.  * VERSION 1.0
  16.  * 
  17.  * Revision 3.5  91/08/13  06:51:29  brennan
  18.  * VERSION .9994
  19.  * 
  20.  * Revision 3.4  91/07/19  07:51:04  brennan
  21.  * escape sequence now recognized in command line assignments
  22.  * 
  23.  * Revision 3.3  91/07/17  10:45:27  brennan
  24.  * changes in command line files -- dictated by posix;
  25.  * Not a big deal, but better this way
  26.  * version 0.9992
  27.  * 
  28.  * Revision 3.2  91/06/28  04:16:43  brennan
  29.  * VERSION 0.999
  30.  * 
  31.  * Revision 3.1  91/06/08  06:14:33  brennan
  32.  * VERSION 0.995
  33.  * 
  34.  * Revision 2.10  91/06/08  06:05:55  brennan
  35.  * When changing main_fin, FINgets had a bozo -- it only worked by a fluke
  36.  * related to the design of zmalloc.  Fixed by returning new value of
  37.  * main_fin from next_main().  Also now mark eof on main_fin differently.
  38.  * 
  39.  * Revision 2.9  91/06/06  09:42:05  brennan
  40.  * added HAVE_FCNTL
  41.  * 
  42.  * Revision 2.8  91/06/04  09:10:50  brennan
  43.  * added some ptr casts
  44.  * 
  45.  * Revision 2.7  91/05/30  09:04:44  brennan
  46.  * input buffer can grow dynamically
  47.  * 
  48.  * Revision 2.6  91/05/28  09:04:48  brennan
  49.  * removed main_buff
  50.  * 
  51.  * Revision 2.5  91/05/23  08:05:51  brennan
  52.  * removed fdopen() proto
  53.  * 
  54.  * Revision 2.4  91/05/22  07:44:10  brennan
  55.  * removed unused variable
  56.  * 
  57.  * Revision 2.3  91/05/15  12:07:36  brennan
  58.  * dval hash table for arrays
  59.  * 
  60.  * Revision 2.2  91/05/06  15:01:04  brennan
  61.  * flush output before fork
  62.  * 
  63.  * Revision 2.1  91/04/08  08:23:09  brennan
  64.  * VERSION 0.97
  65.  * 
  66. */
  67.  
  68. /* fin.c */
  69.  
  70. #include "mawk.h"
  71. #include "fin.h"
  72. #include "memory.h"
  73. #include "bi_vars.h"
  74. #include "field.h"
  75. #include "symtype.h"
  76. #include "scan.h"
  77.  
  78. #if  HAVE_FCNTL_H
  79. #include <fcntl.h>
  80. #endif
  81.  
  82. /* This file handles input buffering */
  83.  
  84. #ifndef MSDOS_MSC
  85. extern int errno ;
  86. #endif
  87. int PROTO(isatty, (int) ) ;
  88.  
  89. static FIN *PROTO( next_main, (int) ) ;
  90. static int  PROTO( is_cmdline_assign, (char *) ) ;
  91. static char *PROTO( enlarge_fin_buffer, (FIN *) ) ;
  92. static void PROTO(set_main_to_stdin, (void) ) ;
  93.  
  94. FIN  *FINdopen( fd, main_flag )
  95.   int fd , main_flag ;
  96. { register FIN *fin = (FIN *) zmalloc( sizeof(FIN) ) ;
  97.  
  98.   fin->fd = fd ;
  99.   fin->flags = main_flag ? MAIN_FLAG : 0 ;
  100.   fin->buffp = fin->buff = (char *) zmalloc(BUFFSZ+1) ;
  101.   fin->nbuffs = 1 ;
  102.   fin->buff[0] = 0 ;
  103.  
  104.   if ( isatty(fd) && rs_shadow.type == SEP_CHAR 
  105.        && rs_shadow.c == '\n' )
  106.   {
  107.     /* interactive, i.e., line buffer this file */
  108.     if ( fd == 0 ) fin->fp = stdin ;
  109.     else
  110.     if ( !(fin->fp = fdopen(fd, "r")) )
  111.     { errmsg(errno, "fdopen failed") ; exit(1) ; }
  112.   }
  113.   else  fin->fp = (FILE *) 0 ;
  114.  
  115.   return fin ;
  116. }
  117.  
  118. FIN  *FINopen( filename, main_flag )
  119.   char *filename ;
  120.   int main_flag ;
  121. { int fd ;
  122.  
  123.   if ( filename[0] == '-' && filename[1] == 0 )
  124.       return  FINdopen(0, main_flag) ;
  125.  
  126. #ifdef THINK_C
  127.   if ( (fd = open( filename , O_RDONLY )) == -1 )
  128. #else
  129.   if ( (fd = open( filename , O_RDONLY, 0 )) == -1 )
  130. #endif
  131.   { errmsg( errno, "cannot open %s" , filename ) ;
  132.     return (FIN *) 0 ; }
  133.  
  134.   return  FINdopen( fd, main_flag ) ;
  135. }
  136.  
  137. void  FINclose( fin )
  138.   register FIN *fin ;
  139. {
  140.   zfree(fin->buff, fin->nbuffs*BUFFSZ + 1) ;
  141.  
  142.   if ( fin->fd )  
  143.         if ( fin->fp )  (void) fclose(fin->fp) ;
  144.         else  (void) close(fin->fd) ;
  145.  
  146.   zfree( fin , sizeof(FIN) ) ;
  147. }
  148.  
  149. /* return one input record as determined by RS,
  150.    from input file (FIN)  fin
  151. */
  152.  
  153. char *FINgets( fin, len_p )
  154.   FIN *fin ;
  155.   unsigned *len_p ;
  156. { register char *p, *q ;
  157.   unsigned match_len ;
  158.   unsigned r ;
  159.  
  160. restart :
  161.  
  162.   if ( ! (p = fin->buffp)[0] )  /* need a refill */
  163.   { 
  164.     if ( fin->flags & EOF_FLAG )
  165.         if ( fin->flags & MAIN_FLAG )
  166.     { fin = next_main(0) ;  goto restart ; }
  167.         else
  168.         { *len_p = 0 ; return (char *) 0 ; }
  169.         
  170.     if ( fin->fp ) /* line buffering */
  171.       if ( ! fgets(fin->buff, BUFFSZ+1, fin->fp) )
  172.       {
  173.         fin->flags |= EOF_FLAG ;
  174.         fin->buff[0] = 0 ;
  175.         fin->buffp = fin->buff ;
  176.         goto restart ;  /* might be main_fin */
  177.       }
  178.       else  /* return this line */
  179.       {
  180.         if ( !(p = strchr(fin->buff, '\n')) )
  181.              p = fin->buff + BUFFSZ + 1 ; /* unlikely to occur */
  182.  
  183.         *p = 0 ; *len_p = p - fin->buff ;
  184.         fin->buffp = p ;
  185. #ifdef THINK_C
  186.     /*
  187.      *  I still don't understand why this is needed, unless fgets()
  188.      *  also does this conversion internally for no good reason.  :-(
  189.      */
  190.         for ( p = fin->buff ; *p ; ++p )
  191.         {
  192.         if (*p == '\n')       *p = '\r';
  193.         else if (*p == '\r')  *p = '\n';
  194.         }
  195. #endif
  196.         return  fin->buff ;
  197.       }
  198.     else  /* block buffering */
  199.     {
  200.       if ( (r = fillbuff(fin->fd, fin->buff, fin->nbuffs*BUFFSZ)) == 0 )
  201.       {
  202.         fin->flags |= EOF_FLAG ;
  203.         fin->buffp = fin->buff ;
  204.         goto restart ; /* might be main */
  205.       }
  206.       else
  207.       if ( r < fin->nbuffs*BUFFSZ )  fin->flags |= EOF_FLAG ;
  208.  
  209.       p = fin->buffp = fin->buff ;
  210.     }
  211.   }
  212.  
  213. retry: 
  214.  
  215.   switch( rs_shadow.type )
  216.   {
  217.     case SEP_CHAR :
  218.             q = strchr(p, rs_shadow.c) ;
  219.             match_len = 1 ;
  220.             break ;
  221.  
  222.     case SEP_STR  :
  223.             q = str_str(p, ((STRING *) rs_shadow.ptr)->str,
  224.                 match_len = ((STRING *) rs_shadow.ptr)->len ) ;
  225.             break ;
  226.  
  227.     case SEP_RE :
  228.             q = re_pos_match(p, rs_shadow.ptr, &match_len) ;
  229.             /* if the match is at the end, there might still be
  230.            more to match in the file */
  231.             if ( q && q[match_len] == 0 && ! (fin->flags & EOF_FLAG))
  232.          q = (char *) 0 ;
  233.             break ;
  234.             
  235.     default :
  236.             bozo("type of rs_shadow") ;
  237.   }
  238.  
  239.   if ( q )
  240.   {  /* the easy and normal case */
  241.      *q = 0 ;  *len_p = q - p ;
  242.      fin->buffp = q + match_len  ;
  243.      return p ;
  244.   }
  245.  
  246.   if ( fin->flags & EOF_FLAG )
  247.   { /* last line without a record terminator */
  248.     *len_p = r = strlen(p) ; fin->buffp = p+r ;
  249.     return p ;
  250.   }
  251.  
  252.   if ( p == fin->buff )  
  253.   { /* current record is too big for the input buffer, grow buffer */
  254.     p = enlarge_fin_buffer(fin) ;
  255.   }
  256.   else
  257.   {
  258.     /* move a partial line to front of buffer and try again */
  259.     unsigned rr ;
  260.  
  261.     p = (char *) memcpy( fin->buff, p, SIZE_T(r = strlen(p)) ) ;
  262.     q = p+r ;  rr = fin->nbuffs*BUFFSZ - r ;
  263.  
  264.     if ( (r = fillbuff(fin->fd, q, rr)) < rr ) fin->flags |= EOF_FLAG ;
  265.   }
  266.   goto retry ;
  267. }
  268.  
  269. static char *enlarge_fin_buffer(fin)
  270.   FIN *fin ;
  271. {
  272.   unsigned r ;
  273.   unsigned oldsize = fin->nbuffs*BUFFSZ+1 ;
  274.  
  275.   fin->buffp = 
  276.   fin->buff = (char *) zrealloc(fin->buff, oldsize, oldsize+BUFFSZ);
  277.   fin->nbuffs++ ;
  278.  
  279.   r = fillbuff(fin->fd, fin->buff + (oldsize-1) , BUFFSZ ) ;
  280.   if ( r < BUFFSZ ) fin->flags |= EOF_FLAG ;
  281.  
  282.   return fin->buff ;
  283. }
  284.  
  285. /*--------
  286.   target is big enough to hold size + 1 chars 
  287.   on exit the back of the target is zero terminated
  288.  *--------------*/
  289. unsigned  fillbuff(fd, target, size)
  290.   int fd ;
  291.   register char *target ;
  292.   unsigned size ;
  293. { register int r ;
  294.   unsigned entry_size = size ;
  295. #ifdef THINK_C
  296.   register char *p = target;
  297. #endif
  298.  
  299.   while ( size )
  300.     switch( r = read(fd, target, size) )
  301.     { case -1 :
  302.         errmsg(errno, "read error") ;
  303.         exit(1) ;
  304.  
  305.       case 0 :
  306.         goto out ;
  307.  
  308.       default :
  309.         target += r ; size -= r ;
  310.         break ;
  311.     }
  312.  
  313. out :
  314.   *target = 0 ;
  315. #ifdef THINK_C
  316.   /*
  317.    *  I still don't understand why this is needed, unless read() also does
  318.    *  this conversion internally for no good reason.  :-(
  319.    */
  320.   for ( ; *p ; ++p )
  321.     {
  322.       if (*p == '\r')
  323.     *p = '\n';
  324.       else if (*p == '\n')
  325.     *p = '\r';
  326.     }
  327. #endif
  328.   return  entry_size - size ;
  329. }
  330.  
  331. /* main_fin is a handle to the main input stream
  332.    == 0  never been opened   */
  333.  
  334. FIN *main_fin ;
  335. ARRAY   Argv ;   /* to the user this is ARGV  */
  336. static double argi = 1.0 ;  /* index of next ARGV[argi] to try to open */
  337.  
  338.  
  339. static void  set_main_to_stdin()
  340. {
  341.     cell_destroy( bi_vars + FILENAME ) ;
  342.     bi_vars[FILENAME].type = C_STRING ;
  343.     bi_vars[FILENAME].ptr = (PTR) new_STRING( "-") ;
  344.     main_fin = FINdopen(0, 1) ;
  345. }
  346.    
  347.  
  348. void  open_main()  
  349. { CELL argc ;
  350.  
  351.   (void) cellcpy(&argc, bi_vars+ARGC) ;
  352.   if ( argc.type != C_DOUBLE ) cast1_to_d(&argc) ;
  353.  
  354.   if ( argc.dval == 1.0 )  set_main_to_stdin() ;
  355.   else  (void)  next_main(1) ;
  356. }
  357.  
  358. static  FIN  *next_main(open_flag)
  359.   int open_flag ; /* called by open_main() if on */
  360.   register CELL *cp ;
  361.   CELL   argc ;  /* copy of ARGC */
  362.   CELL   c_argi ; /* cell copy of argi */
  363.   CELL   argval ;    /* copy of ARGV[c_argi] */
  364.  
  365.  
  366.   argval.type = C_NOINIT ;
  367.   c_argi.type = C_DOUBLE ;
  368.  
  369.   if ( main_fin )  FINclose(main_fin) ;
  370.   cell_destroy( bi_vars + FILENAME ) ;
  371.   cell_destroy( bi_vars + FNR ) ;
  372.   bi_vars[FNR].type = C_DOUBLE ;
  373.   bi_vars[FNR].dval = 0.0 ;
  374.  
  375.   if ( cellcpy(&argc, &bi_vars[ARGC])->type != C_DOUBLE )
  376.           cast1_to_d(&argc) ;
  377.   
  378.   while ( argi < argc.dval )
  379.   {
  380.     c_argi.dval = argi ;
  381.     argi += 1.0 ;
  382.  
  383.     if ( !(cp = array_find( Argv, &c_argi, NO_CREATE)) )
  384.         continue ; /* its deleted */
  385.  
  386.     /* make a copy so we can cast w/o side effect */
  387.     cell_destroy(&argval) ;
  388.     cp = cellcpy(&argval, cp) ;
  389.     if ( cp->type < C_STRING )  cast1_to_s(cp) ;
  390.     if ( string(cp)->len == 0 )  continue ;
  391.  
  392.     /* it might be a command line assignment */
  393.     if ( is_cmdline_assign(string(cp)->str) )  continue ;
  394.  
  395.     /* try to open it -- we used to continue on failure, 
  396.        but posix says we should quit */
  397.     if ( ! (main_fin = FINopen( string(cp)->str, 1 )) ) exit(1) ;
  398.  
  399.     /* success */
  400.     (void) cellcpy( &bi_vars[FILENAME] , cp ) ;
  401.     free_STRING( string(cp) ) ;
  402.     return  main_fin ;
  403.   }
  404.   /* failure */
  405.   cell_destroy(&argval) ;
  406.  
  407.   if ( open_flag )  /* all arguments were null or assignment */
  408.   { set_main_to_stdin() ;  return  main_fin ; }
  409.     
  410.   /* real failure */
  411.   bi_vars[FILENAME].type = C_STRING ;
  412.   bi_vars[FILENAME].ptr = (PTR) new_STRING( "" ) ;
  413.  
  414.   { /* this is how we mark EOF on main_fin  */
  415.     static char dead_buff = 0 ;
  416.     static FIN  dead_main = {0, (FILE*)0, &dead_buff, &dead_buff,
  417.        1, EOF_FLAG} ;
  418.  
  419.     return  main_fin = &dead_main ;
  420.     /* since MAIN_FLAG is not set, FINgets won't call next_main() */
  421.   }
  422. }
  423.     
  424.  
  425. static int is_cmdline_assign(s)
  426.   char *s ;
  427.   register char *p ;
  428.   int c ;
  429.   SYMTAB *stp ;
  430.   CELL *cp ;
  431.   unsigned len ;
  432.  
  433.   if ( scan_code[*(unsigned char *)s] != SC_IDCHAR ) return 0 ;
  434.  
  435.   p = s+1 ;
  436.   while ( (c = scan_code[*(unsigned char*)p]) == SC_IDCHAR 
  437.       || c == SC_DIGIT ) p++ ;
  438.  
  439.   if ( *p != '=' )  return 0 ;
  440.  
  441.   *p = 0 ;
  442.   stp = find(s) ;
  443.  
  444.   switch( stp->type )
  445.   {
  446.     case  ST_NONE :
  447.         stp->type = ST_VAR ;
  448.         stp->stval.cp = cp = new_CELL() ;
  449.         break ;
  450.  
  451.     case  ST_VAR :
  452.         cp = stp->stval.cp ;
  453.         break ;
  454.  
  455.     default :
  456.         rt_error(
  457.           "cannot command line assign to %s\n\t- type clash or keyword" 
  458.           , s ) ;
  459.   }
  460.   
  461.   /* we need to keep ARGV[i] intact */
  462.   *p++ = '=' ;
  463.   len = strlen(p)+1 ;
  464.   /* posix says escape sequences are on from command line */
  465.   p = rm_escape( strcpy((char*)zmalloc(len), p) ) ;
  466.   cp->ptr = (PTR) new_STRING(p) ;
  467.   zfree(p,len) ;
  468.   check_strnum(cp) ;
  469.   return 1 ;
  470. }
  471.